using System;
using System.Collections.Generic;
using System.Text;

using Pacman.Simulator;
using Pacman.Simulator.Ghosts;
using NeuralNetwork;
using System.Drawing;

namespace Pacman.Implementations
{
	public class TestAI : BasePacman
	{
		public TestAI() : base("TestAI","1") { }

		private bool debug = false;
		private List<Sector> sectors = null;

		public override void Draw(Graphics g) {
			foreach( Sector sector in sectors ) {
				double danger = sector.GetDanger() * 510;
				int green = 255;
				int red = 0;
				if( danger < 255 ) {
					red += (int)danger;
				} else {
					red = 255;
					green -= ((int)danger - 255);
				}
				g.FillRectangle(new SolidBrush(Color.FromArgb(100, red, green, 0)), new Rectangle(Sector.GameState.Map.Nodes[sector.X, sector.Y].CenterX, Sector.GameState.Map.Nodes[sector.X, sector.Y].CenterY, sector.Width * 9, sector.Height * 9));
			}
		}

		public override Direction Think(GameState gs) {
			Sector.GameState = gs;
			if( sectors == null ) {
				sectors = new List<Sector>();
				sectors.Add(Sector.GetSector(0, 0, 13, 9));
				sectors.Add(Sector.GetSector(14, 0, 13, 9));
				sectors.Add(Sector.GetSector(0, 10, 8, 8));
				// sectors.Add(new sector(9,10,9,8)); // mid-sector not at good target
				sectors.Add(Sector.GetSector(19, 10, 8, 8));
				sectors.Add(Sector.GetSector(0, 19, 13, 10));
				sectors.Add(Sector.GetSector(14, 19, 13, 10));
			}			
			// sectors ...
			Prediction prediction = new Prediction(gs, 6);
			foreach( Sector s in sectors ) {
				s.Danger = 0f;
			}
			Sector pacSector = null;
			foreach( Prediction.DangerMap dm in prediction.DangerMaps ) {
				foreach( Sector s in sectors ) {
					if( s.Contains(gs.Pacman.Node) ) {
						pacSector = s;
					}
					for( int dx = s.X; dx < s.X + s.Width; dx++ ) {
						for( int dy = s.Y; dy < s.Y + s.Height; dy++ ) {
							s.Danger += dm.Danger[dx, dy];
						}
					}
				}
			}
			sectors.Sort(new Comparison<Sector>(delegate(Sector s1, Sector s2){
				if( s1.GetNormalizedDanger() == s2.GetNormalizedDanger() ) return 0;
				if( s1.GetNormalizedDanger() > s2.GetNormalizedDanger() ) return 1;
				return -1;
			}));
			// danger
			double[] dist = { Double.PositiveInfinity, Double.PositiveInfinity, Double.PositiveInfinity, Double.PositiveInfinity };
			// calculate danger for each direction
			foreach( Ghost ghost in gs.Ghosts ) {
				if( ghost.Node == null ) {
					continue;
				}
				Node.PathInfo path = gs.Pacman.Node.ShortestPath[ghost.Node.X, ghost.Node.Y];
				if( path != null ) {
					if( (ghost.Node.ShortestPath[gs.Pacman.Node.X, gs.Pacman.Node.Y].Direction != ghost.InverseDirection(ghost.Direction) || path.Distance < 2) && // heading towards pacman
						path.Distance < dist[(int)path.Direction] &&
						path.Distance < 4 && // magic number
						(ghost.Chasing || ghost.RemainingFlee < 200 || ghost.Entering) ) {
						dist[(int)path.Direction] = path.Distance;
					}
				}
			}
			// calculate best
			List<Direction> possibleDirections = new List<Direction>();
			for( int i = 0; i < dist.Length; i++ ) {
				if( gs.Pacman.PossibleDirection((Direction)i) && dist[i] == Double.PositiveInfinity ) {
					possibleDirections.Add((Direction)i);
				}
			}
			// 0 => choose least dangerous // still needs more intelligence
			if( possibleDirections.Count == 0 ) {
				Direction bestDirection = Direction.None;
				double bestDistance = 0.0;
				for( int i = 0; i < dist.Length; i++ ) {
					if( gs.Pacman.PossibleDirection((Direction)i) && dist[i] > bestDistance ) {
						bestDirection = (Direction)i;
						bestDistance = dist[i];
					}
				}
				if( debug ) Console.WriteLine("0 options: " + bestDirection);
				return bestDirection;
			}
				// 1 => choose just that
			else if( possibleDirections.Count == 1 ) {
				if( debug ) Console.WriteLine("1 option: " + possibleDirections[0]);
				return possibleDirections[0];
			}
				// 2+ => choose ... ?
			else {
				if( debug ) Console.Write(possibleDirections.Count + " options: ");
				if( debug ) foreach( Direction d in possibleDirections ) Console.Write(d + ", ");
				if( debug ) Console.WriteLine("");
				Node.PathInfo bestPath = null;
				Node bestNode = null;
				// change sector
				Sector curSector = Sector.Contains(sectors, gs.Pacman.Node);
				if( curSector == null || curSector.GetNormalizedDanger() > 0.1 ) {
					foreach( Sector sector in sectors ) {
						Node center = gs.Map.Nodes[sector.TargetX, sector.TargetY];
						Node nonWallCenter = gs.Map.GetNodeNonWall(center.CenterX, center.CenterY);
						Node.PathInfo path = gs.Pacman.Node.ShortestPath[nonWallCenter.X, nonWallCenter.Y];
						if( path != null ) {
							foreach( Direction d in possibleDirections ) {
								if( d == path.Direction ) {
									bestPath = path;
									goto pathFound;
								}
							}
						}
					}
				}
			pathFound:
				// hunt pills
				if( bestPath == null ) {
					foreach( Node node in gs.Map.Nodes ) {
						if( node.Type != Node.NodeType.Wall ) {
							if( node.Type == Node.NodeType.Pill || node.Type == Node.NodeType.PowerPill ) {
								Node.PathInfo curPath = gs.Pacman.Node.ShortestPath[node.X, node.Y];
								if( curPath != null ) {
									curPath = curPath.Clone();
								} else {
									continue;
								}
								if( curPath.Direction == gs.Pacman.InverseDirection(gs.Pacman.Direction) ) {
									curPath = new Node.PathInfo(curPath.Direction, curPath.Distance + 1);
								}
								if( curPath != null && (bestPath == null || curPath.Distance <= bestPath.Distance) ) {
									foreach( Direction d in possibleDirections ) {
										if( d == curPath.Direction ) {
											//if( bestPath == null || curPath.Distance < bestPath.Distance || (bestPath.Distance == curPath.Distance && GameState.Random.NextDouble() < 0.5) ) {
											bestNode = node;
											bestPath = curPath;
											if( debug ) Console.WriteLine("best pill: " + bestPath.Direction);
											break;
											//}
										}
									}
								}
							}
						}
					}
				}
				// return if found
				if( bestPath != null ) {
					if( debug ) Console.WriteLine("best: " + bestPath.Direction);
					return bestPath.Direction;
				}
				// follow same direction if it is in possibles
				foreach( Direction d in possibleDirections ) {
					if( d == gs.Pacman.Direction ) {
						if( debug ) Console.WriteLine("follow direction: " + d);
						return d;
					}
				}
				// otherwise choose randomly (?)
				int chosen = GameState.Random.Next(0, possibleDirections.Count - 1);
				if( debug ) Console.WriteLine("random: " + possibleDirections[chosen]);
				return possibleDirections[chosen];
			}
		}
	}
}
